﻿using ldhWebApiWF.database;
using ldhWebApiWF.models;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Core;
using MongoDB.Driver.Builders;
using MongoDB.Driver.Operations;
using MongoDB.Driver.Linq;
using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Http.Description;
using MongoDB.Driver.GridFS;

namespace ldhWebApiWF.Controller
{
    // Allow CORS for all origins. (Caution!)
    //[EnableCors(origins: "*", headers: "*", methods: "*")]
    //[EnableCors(origins: "http://www.contoso.com,http://www.example.com", headers: "accept,content-type,origin,x-my-header", methods: "get,post")]
    [RoutePrefix("fs")]
    public class GridFSController : ApiController
    {
        IGridFSBucket bucket;

        public GridFSController()
        {
            bucket = BaseManager.GetGridFSBucket("Gridfsdb");
        }

        [HttpPost]
        [Route("file/upload")]
        public async Task<IHttpActionResult> UploadFile()
        {
            if (!Request.Content.IsMimeMultipartContent())
            {
                return StatusCode(HttpStatusCode.UnsupportedMediaType);
            }

            var path = AppDomain.CurrentDomain.BaseDirectory + "uploads\\";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            var provider = new MultipartFormStreamProvider(path);
            try
            {
                await Request.Content.ReadAsMultipartAsync(provider);
                if (provider.FileData.Count == 0)
                {
                    ModelState.AddModelError(Guid.NewGuid().ToString(), "服务器不支持的文件类型");
                    return BadRequest(ModelState);
                }
                foreach (MultipartFileData fileData in provider.FileData)
                {
                    var fileName = Extens.TakeFileName(fileData.Headers.ContentDisposition.FileName);
                    if (string.IsNullOrEmpty(fileName))
                    {
                        ModelState.AddModelError(Guid.NewGuid().ToString(), "文件名不能空");
                        return BadRequest(ModelState);
                    }
                    if (Path.GetInvalidFileNameChars().Where(x => fileName.Contains(x)).Any())
                    {
                        ModelState.AddModelError(Guid.NewGuid().ToString(), "文件名中含有非法字符");
                        return BadRequest(ModelState);
                    }
                    var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, fileName);
                    using (var cursor = await bucket.FindAsync(filter))
                    {
                        var fileInfo = (await cursor.ToListAsync()).FirstOrDefault();
                        if (fileInfo != null)
                        {
                            ModelState.AddModelError(Guid.NewGuid().ToString(), "该文件已存在于服务器");
                            return BadRequest(ModelState);
                        }
                    }
                    if(File.Exists(path + fileName))
                    {
                        File.Delete(path + fileName);
                    }
                    await Task.Run(() => {
                        //把缓存文件移动至正式文件夹
                        File.Move(fileData.LocalFileName, path + fileName);
                    });
                    var options = new GridFSUploadOptions
                    {
                        Metadata = new BsonDocument
                            {
                                { "own", "jac" },
                                { "copyrighted", true }
                            }
                    };
                    using (var source = new FileStream(path + fileName, FileMode.Open, FileAccess.Read))
                    {
                        var id = await bucket.UploadFromStreamAsync(fileName, source, options);
                    }
                }
            }
            catch (Exception e)
            {
                ModelState.AddModelError(Guid.NewGuid().ToString(), e.Message);
                return BadRequest(ModelState);
            }
            return Ok();
        }

        [HttpGet]
        [Route("file/download/byid/{id}")]
        public async Task<IHttpActionResult> DownloadFileById(string id)
        {
            if (String.IsNullOrEmpty(id))
                return StatusCode(HttpStatusCode.BadRequest);

            ObjectId oid;
            if (!ObjectId.TryParse(id, out oid))
            {
                ModelState.AddModelError(Guid.NewGuid().ToString(), "id不是有效的objectid");
                return BadRequest(ModelState);
            }
            
            var filter = Builders<GridFSFileInfo>.Filter.Eq("_id", oid);
            string fn;
            using (var cursor = await bucket.FindAsync(filter))
            {
                var fileInfo = (await cursor.ToListAsync()).FirstOrDefault();
                if (fileInfo == null)
                {
                    ModelState.AddModelError(Guid.NewGuid().ToString(), "该文件不存在于服务器");
                    return BadRequest(ModelState);
                }
                fn = fileInfo.Filename;
            }

            var mime = new MediaTypeHeaderValue(Extens.GetMimeType(Path.GetExtension(fn)));

            var bytes = await bucket.DownloadAsBytesAsync(ObjectId.Parse(id));
            var memStream = new MemoryStream(bytes);

            if (Request.Headers.Range != null)
            {
                try
                {
                    var partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent);
                    partialResponse.Content = new ByteRangeStreamContent(memStream, Request.Headers.Range, mime);
                    return ResponseMessage(partialResponse);
                }
                catch (InvalidByteRangeException invalidByteRangeException)
                {
                    return StatusCode(HttpStatusCode.RequestedRangeNotSatisfiable);
                }
            }
            else
            {
                var fullResponse = Request.CreateResponse(HttpStatusCode.OK);
                fullResponse.Content = new StreamContent(memStream);
                fullResponse.Content.Headers.ContentType = mime;
                return ResponseMessage(fullResponse);
            }
        }

        [HttpGet]
        [Route("file/download/byname/{filename}")]
        public async Task<IHttpActionResult> DownloadFileByName(string filename)
        {
            if (String.IsNullOrEmpty(filename))
                return StatusCode(HttpStatusCode.BadRequest);

            var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, filename);
            using (var cursor = await bucket.FindAsync(filter))
            {
                var fileInfo = (await cursor.ToListAsync()).FirstOrDefault();
                if (fileInfo == null)
                {
                    ModelState.AddModelError(Guid.NewGuid().ToString(), "该文件不存在于服务器");
                    return BadRequest(ModelState);
                }
            }

            var mime = new MediaTypeHeaderValue(Extens.GetMimeType(Path.GetExtension(filename)));

            var bytes = await bucket.DownloadAsBytesByNameAsync(filename);
            var memStream = new MemoryStream(bytes);

            if (Request.Headers.Range != null)
            {
                try
                {
                    var partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent);
                    partialResponse.Content = new ByteRangeStreamContent(memStream, Request.Headers.Range, mime);
                    return ResponseMessage(partialResponse);
                }
                catch (InvalidByteRangeException invalidByteRangeException)
                {
                    return StatusCode(HttpStatusCode.RequestedRangeNotSatisfiable);
                }
            }
            else
            {
                var fullResponse = Request.CreateResponse(HttpStatusCode.OK);
                fullResponse.Content = new StreamContent(memStream);
                fullResponse.Content.Headers.ContentType = mime;
                return ResponseMessage(fullResponse);
            }
        }

        ////[ActionName("DefaultAction")] //Map Action and you can name your method with any text
        //// GET api/books
        ////[DeflateCompression]//using zlib compression
        //[Route("books")]
        //public async Task<IHttpActionResult> GetBooks()
        //{
        //    //禁止使用decimal，转用double型
        //    //var names = await books
        //    //    .Find(x => x.Price >50 && x.Price <300)
        //    //    .ToListAsync();
        //    //return Ok(names);

        //    //v2.1
        //    //var names = books.AsQueryable().Where(x => x.Price >= 200 && x.Price <= 300);

        //    //int pageSize = 500;
        //    //var totalRecord = await books.CountAsync(new BsonDocument());
        //    //var totalPage = (totalRecord + pageSize - 1) / pageSize;
        //    ////2.0
        //    ////var names = await books.Find(new BsonDocument()).Skip((int)totalPage).Limit(50).ToListAsync();
        //    ////2.1
        //    //var names = books.AsQueryable().Skip((int)totalPage * 0).Take(pageSize);

        //    //日期时间操作提交时必须是utc时间
        //    //日期时间查询时必须先转为本地时间
        //    var start = DateTime.Parse("2015-10-17T11:11:29").ToLocalTime();
        //    var end = DateTime.Parse("2015-10-17T12:12:20").ToLocalTime();
        //    //2.0
        //    //var names = await books.Find(x => x.ReleaseDate >= start && x.ReleaseDate <= end).ToListAsync();
        //    //2.1
        //    var names = await books.Find(b => b.ReleaseDate >= start && b.ReleaseDate <= end).ToListAsync();

        //    return Ok(names);

        //    //var bks = await books.Find(new BsonDocument()).ToListAsync();
        //    //return Ok(bks);
        //}

        ////// GET api/books/5
        //[Route("books/{id}")]
        ////[ResponseType(typeof(Book))]
        //public async Task<IHttpActionResult> GetBook(string id)
        //{
        //    //身份验证
        //    //var pwd = Request.Headers.SingleOrDefault(h => h.Key == "pwd");
        //    //if (pwd.Value.FirstOrDefault() != "123")
        //    //{
        //    //    return StatusCode(HttpStatusCode.NotFound);
        //    //}

        //    ObjectId oid;
        //    if (!ObjectId.TryParse(id, out oid))
        //    {
        //        return StatusCode(HttpStatusCode.BadRequest);
        //    }
        //    var book = await books.Find(new BsonDocument("_id",oid)).FirstOrDefaultAsync();
        //    if (book == null)
        //    {
        //        return NotFound();
        //    }

        //    //return Ok(book);
        //    return Ok(book.ToJson());
        //}

        //// PUT api/books/5
        //[Route("books/{id}")]
        //[HttpPut]
        //public async Task<IHttpActionResult> PutBook(string id, Book book)
        //{
        //    if (!ModelState.IsValid)
        //    {
        //        return BadRequest(ModelState);
        //    }

        //    if (!await BookExists(id))
        //    {
        //        return NotFound();
        //    }

        //    //var result = await books.FindOneAndUpdateAsync(x=>x.Id == ObjectId.Parse(id), Builders<Book>.Update.Set(x => x.Price, book.Price));
        //    var dbbook = await books.Find(x => x.Id == ObjectId.Parse(id)).SingleAsync();
        //    dbbook.Genre = book.Genre;
        //    dbbook.Price = book.Price;
        //    dbbook.Title = book.Title;
        //    var result = await books.ReplaceOneAsync(x => x.Id == ObjectId.Parse(id), dbbook);
        //    return StatusCode(HttpStatusCode.NoContent);
        //}

        ////// POST api/BookApi
        ////[ActionName("DefaultAction")]
        //[Route("books")]
        //[HttpPost]
        //[ResponseType(typeof(Book))]
        //public async Task<IHttpActionResult> PostBook(Book book)
        //{
        //    if (!ModelState.IsValid)
        //    {
        //        return BadRequest(ModelState);
        //    }
        //    //时区+8
        //    //book.ReleaseDate = book.ReleaseDate.AddHours(8);
        //    //Stopwatch sw = Stopwatch.StartNew();
        //    await books.InsertOneAsync(book);
        //    //Console.WriteLine(sw.ElapsedMilliseconds);

        //    //List<Book> bks = new List<Book>();
        //    //for (int i = 0; i < 20; i++)
        //    //{
        //    //    bks.Add(new Book() { Title = "Gizmo", Price = 300, Genre = "Widget", ReleaseDate = DateTime.Now, staute = em_staute.好, author = new Author() { Name = "jacob" } });
        //    //}
        //    //Stopwatch sw = Stopwatch.StartNew();
        //    //await books.InsertManyAsync(bks);
        //    //Console.WriteLine(sw.ElapsedMilliseconds);
        //    return Ok(book);
        //}

        //// DELETE api/BookApi/5
        //[Route("books/{id}")]
        //[HttpDelete]
        //[ResponseType(typeof(Book))]
        //public async Task<IHttpActionResult> DeleteBook(string id)
        //{
        //    if (!await BookExists(id))
        //    {
        //        return NotFound();
        //    }

        //    var result = await books.DeleteOneAsync(x => x.Id == ObjectId.Parse(id));

        //    return Ok(result);
        //}

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        //private async Task<bool> BookExists(string id)
        //{
        //    ObjectId outId;
        //    if (ObjectId.TryParse(id, out outId))
        //    {
        //        if (await books.CountAsync(x => x.Id == outId) > 0)
        //        {
        //            return true;
        //        }
        //    }
        //    return false;
        //}
    }
}
